/**
* Code heavily modified from Nash
* License GPL
* Website http://nashruddin.com
*/

#include <stdio.h>
#include <string>
#include "cv.h"
#include "highgui.h"
#include <time.h>

// Keep track of the detected feature count. An increment of 1 is the idea count for a match.
int fcount = 0;
int lastfcount = 0;

int currentFace = 0;

char * Overlay = "";
char * subOverlay = "";
char * checkOverlay = "";

time_t tChange = NULL;
time_t tLastChange = NULL;


// Haars for feature detection. Names are self-explanatory.
CvHaarClassifierCascade * faceRegion = (CvHaarClassifierCascade *) cvLoad("haarcascade_frontalface_default.xml");
CvHaarClassifierCascade * fCascade = (CvHaarClassifierCascade *) cvLoad("smiled_01.xml");

CvMemStorage * storage = cvCreateMemStorage(0);

int main( int argc, char **argv )
{
    CvCapture *capture = 0;
    IplImage  *frame = 0;
    int       key = 0;

    CvFont font;
    cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX,1,1,0,1);

    capture = cvCaptureFromCAM( 0 );

    /* always check */
    if ( !capture ) {
        fprintf( stderr, "Cannot initialize webcam!\n" );
        return 1;
    }

    /* create a window for the video */
    cvNamedWindow( "Anti-spoof test", CV_WINDOW_AUTOSIZE );

    while( key != 'q' ) {
        frame = cvQueryFrame( capture );

        /* always check */
        if( !frame ) break;

        cvSmooth(frame,frame);
        CvSeq * faceObj = cvHaarDetectObjects(
            frame,
            faceRegion,
            storage,
            1.1, 5, CV_HAAR_DO_CANNY_PRUNING,      // scale factor, min neighbors (groups of X get merged to one, for faces this should be pretty high), and pruning flag
            cvSize(80, 80)                         // minimum detection scale
        );

        for(int i = 0; i < faceObj->total; i++ ) {
            CvRect * s = (CvRect*)cvGetSeqElem(faceObj, i);

            cvRectangle(
                frame,
                cvPoint(s->x, s->y),
                cvPoint(s->x + s->width, s->y + s->height),
                CV_RGB(255, 0, 0),
                1, 8, 0
                );
        }


        if (faceObj->total >= 1){
            currentFace = 1;

        CvRect * face = (CvRect*)cvGetSeqElem(faceObj, 0);

        cvRectangle(
            frame,
            cvPoint(face->x, face->y),
            cvPoint(face->x + face->width,face->y + face->height),
        CV_RGB(255, 0, 0),
        1, 8, 0
        );

        //cvClearMemStorage(storage);

// This is an attempt to only search a specified part of the image for the feature.
        cvSetImageROI(
            frame,                    /* the source image */
            cvRect(
                face->x + (face->width / 4),                    /* x = start from left-center */
                face->y + (2*face->width / 3),                  /* y = start from a bit below the nose */
                face->width/2,        /* width = a bit smaller than the head diameter */
                face->height/3        /* height = the height of a mouth */
            )
        );

        //uncomment to highlight the ROI for debugging
        //cvNot(frame, frame);

        Overlay = "Face detected";
        subOverlay = "awaiting change detection...";
        tLastChange = NULL;
        }
        else{
            currentFace = 0;
            Overlay = "No face detected";
            subOverlay = "";
        }

        if (currentFace){

        CvSeq * fSeq = cvHaarDetectObjects(frame,fCascade,storage,1.1,4,CV_HAAR_DO_CANNY_PRUNING,cvSize(43,19));

        for(int i = 0; i < fSeq->total; i++ ) {
            CvRect * s = (CvRect*)cvGetSeqElem(fSeq, i);

            cvRectangle(
                frame,
                cvPoint(s->x, s->y),
                cvPoint(s->x + s->width, s->y + s->height),
                CV_RGB(0, 255, 0),
                1, 8, 0
                );
        }

        if (fSeq->total != lastfcount){
            lastfcount = fcount;
            fcount = fSeq->total;
            tLastChange = tChange;
            tChange = time(NULL);
            std::cout << fcount << " at " << tChange << "\n";
            if (currentFace == 1 && (tChange - tLastChange > 3) && (tLastChange != NULL))
                checkOverlay = "Change detected, physical face verified.";
            }
        }
        cvResetImageROI(frame);

        cvPutText(frame,Overlay,cvPoint(50,50),&font,cvScalar(255,255,255));
        cvPutText(frame,subOverlay,cvPoint(50,100),&font,cvScalar(0,255,0));
        cvPutText(frame,checkOverlay,cvPoint(50,150),&font,cvScalar(255,0,0));
        cvShowImage( "Anti-spoof test", frame );

        if (key == 'c') {
            cvSaveImage("me.png", frame);
            key = -1;
            }

        if (key == 'a') {
            checkOverlay = "";
            key = -1;
            }

        key = cvWaitKey( 1 );
        }
    /* free memory */
    cvDestroyWindow( "Anti-spoof test" );
    cvReleaseCapture( &capture );
    cvClearMemStorage(storage);

    return 0;
}
